package com.thoughtorigin.reflect {
import com.thoughtorigin.reflect.metareadermocks.MultipleMetaDataSample;
import com.thoughtorigin.reflect.metareadermocks.Sample1;

import flash.utils.describeType;

import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertNotNull;

public class DescribeMetaReaderTest {

    private var _reader: DescribeMetaReader;
    private var _describer: Function;

    [Before]
    public function setUp(): void {
        _describer = describeType;
        _reader = new DescribeMetaReader();
    }

    [After]
    public function tearDown(): void {
        _reader = null;
    }

    [Test]
    public function shouldReadClassMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertNotNull(metaData);
            assertNotNull(metaData.classMetaData);
            assertEquals("ClassMetaData", ConstructorMetaData(metaData.classMetaData["ClassMetaData"]).metaDataName);
        }

        _reader.populateMetaData(describeType(Sample1), callback);
    }

    [Test]
    public function shouldGetClassName(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertEquals("com.thoughtorigin.reflect.metareadermocks::Sample1", metaData.className);
        }

        _reader.populateMetaData(describeType(Sample1), callback);
    }

    [Test]
    public function shouldGetFunctionMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertNotNull(metaData.functionMetaData);
            assertEquals("sampleFunction", FunctionMetaDataItem(metaData.functionMetaData["sampleFunction"][1]).functionName);
            assertEquals("FunctionMetaData", FunctionMetaDataItem(metaData.functionMetaData["sampleFunction"][1]).metaDataName);
            assertEquals(0, FunctionMetaDataItem(metaData.functionMetaData["sampleFunction"][0]).metaArgs.length);

        }

        _reader.populateMetaData(describeType(Sample1), callback);
    }

    [Test]
    public function shouldGetPropertyMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertNotNull(metaData.propertyMetaData);
            assertEquals("sampleSetter", PropertyMetaDataItem(metaData.propertyMetaData["sampleSetter"][0]).functionName);
            assertEquals("PropertySetMetaData", PropertyMetaDataItem(metaData.propertyMetaData["sampleSetter"][0]).metaDataName);
            assertEquals(PropertyAccess.WRITE_ONLY, PropertyMetaDataItem(metaData.propertyMetaData["sampleSetter"][0]).access);

            assertEquals("sampleGetter", PropertyMetaDataItem(metaData.propertyMetaData["sampleGetter"][0]).functionName);
            assertEquals("PropertyGetMetaData", PropertyMetaDataItem(metaData.propertyMetaData["sampleGetter"][0]).metaDataName);
            assertEquals(PropertyAccess.READ_ONLY, PropertyMetaDataItem(metaData.propertyMetaData["sampleGetter"][0]).access);

            assertEquals("sampleProperty", PropertyMetaDataItem(metaData.propertyMetaData["sampleProperty"][0]).functionName);
            assertEquals("FullAccessProperty", PropertyMetaDataItem(metaData.propertyMetaData["sampleProperty"][0]).metaDataName);
            assertEquals(PropertyAccess.READ_WRITE, PropertyMetaDataItem(metaData.propertyMetaData["sampleProperty"][0]).access);


        }

        _reader.populateMetaData(describeType(Sample1), callback);
    }

    [Test]
    public function shouldStoreMultipleMetaDataPerClass(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            var counter:uint = 0;
            for(var key:String in metaData.classMetaData){
                counter++;    
            }
            assertEquals(5, counter);
            assertEquals("Fry", ConstructorMetaData(metaData.classMetaData["Fry"]).metaDataName);
            assertEquals("Leela", ConstructorMetaData(metaData.classMetaData["Leela"]).metaDataName);
            assertEquals("Zoidberg", ConstructorMetaData(metaData.classMetaData["Zoidberg"]).metaDataName);

        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }

    [Test]
    public function shouldStoreMultipleMetaDataPerFunction():void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertEquals(4, metaData.functionMetaData["simponsFunction"].length);
            assertEquals(6, metaData.functionMetaData["archerFunction"].length);
        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }
    [Test]
    public function shouldStoreMultipleMetaDataPerProperty():void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            assertEquals(4, metaData.propertyMetaData["propertyZim"].length);
        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }

    [Test]
    public function shouldStoreMetaDataArgumentsPerClassMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            var c: ConstructorMetaData = metaData.classMetaData["Zoidberg"];
            assertEquals(2, c.metaArgs.length);
            assertEquals("type", MetaArg(c.metaArgs[0]).key);
            assertEquals("lobster", MetaArg(c.metaArgs[0]).value);
        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }

    [Test]
    public function shouldStoreMetaDataArgumentsPerFunctionMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            var metaDataItems: Array = metaData.functionMetaData["archerFunction"];
            for each(var metaDataItem: FunctionMetaDataItem in metaDataItems) {
                if(metaDataItem.metaDataName == "Pam") {
                    assertEquals("true", MetaArg(metaDataItem.metaArgs[0]).value);
                    assertEquals("gossip", MetaArg(metaDataItem.metaArgs[0]).key);
                }
            }
        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }

    [Test]
    public function shouldStoreMetaDataArgumentsPerPropertyMetaData(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            var metaDataItems: Array = metaData.functionMetaData["propertyZim"];
            for each(var metaDataItem: PropertyMetaDataItem in metaDataItems) {
                if(metaDataItem.metaDataName == "Gir") {
                    assertEquals("false", MetaArg(metaDataItem.metaArgs[0]).value);
                    assertEquals("knowsWhatGStandsFor", MetaArg(metaDataItem.metaArgs[0]).key);
                }
            }
        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }

    [Test]
    public function shouldPassDecoratedPropertyName(): void {
        var callback: Function = function(): void {
            var metaData: ObjectMetaData = _reader.classMetaData;
            var c: ConstructorMetaData = metaData.classMetaData["Zoidberg"];
            assertEquals("com.thoughtorigin.reflect.metareadermocks::MultipleMetaDataSample", c.decoratedPropertyName);

            var metaDataItems: Array = metaData.functionMetaData["archerFunction"];
            for each(var metaDataItem: FunctionMetaDataItem in metaDataItems) {
                if(metaDataItem.metaDataName == "Pam") {
                    assertEquals("archerFunction", metaDataItem.decoratedPropertyName);
                }
            }

            metaDataItems = metaData.functionMetaData["propertyZim"];
            for each(metaDataItem in metaDataItems) {
                if(metaDataItem.metaDataName == "Gir") {
                    assertEquals("propertyZim", metaDataItem.decoratedPropertyName);
                }
            }

        }
        _reader.populateMetaData(describeType(MultipleMetaDataSample), callback);
    }
}
}